/*******************************************************************
made by Johannes Philippi, Feb. 2007
johannesphilippi[a t]web[d o t]de

This is a very simple program which demonstrates basic 
CAN functionality:
	- configuring the CAN driver (250kBit/s)
	- configuring MessageObjects (in extended frame format)
	- sending a message on the CAN (switch-controlled)
	- receiving a message from the CAN (interrupt-controlled)
	- handling ID-tags and masks
The display is ued to output some information (incoming IDs) and 
for signaling transmit and receive activities.
*******************************************************************/

#include <avr/io.h>           	//names of bytes and bits of I/O registers
#include <inttypes.h>			//AVR style type definitions
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <string.h>
#include "env_dev.h"
#include "cross.h"  // all cross functions
#include "can.h"


/*******************************************************************
definitions
*******************************************************************/
#define NO_MOBS 15		// number of message objects
#define NOMOB   0xff
#define TX_MOB 3

/*******************************************************************
globals
*******************************************************************/

CAN_messageType recMsg;


/*******************************************************************
Get idex of MOb for which an interrupt was detected.
*******************************************************************/
uint8_t getmob( uint32_t bitmask) 
{
 uint8_t mob;

 if( bitmask==0) return NOMOB;

 //the bitmask is shifted to the rigth until the LSB is one
 //the number of such shift operations is the index of the MOb
 for( mob=0; (bitmask & 0x01)==0; bitmask >>= 1, ++mob);

 //security check
 if ( mob > 14 ) return NOMOB;
 	else return mob;
}     

/*******************************************************************
CAN Receive Interrupt Service Routine
*******************************************************************/
SIGNAL(SIG_CAN_INTERRUPT1)
{
//CAN_messageType recMsg; this is a global variable
uint8_t save_canpage = CANPAGE;		// store current CANPAGE
uint8_t mob,i;
	// get the index of the MOb for which the interrupt occured
	mob = getmob(CANSIT2 | (CANSIT1 << 8));
		if( mob == NOMOB )   return;
   	
	//select concerned MOb page
	CANPAGE = mob << 4;	

	if (CANSTMOB & (1<<TXOK))				// signaling txOK
		{		 	
		 	CANSTMOB &= ~(1<<TXOK);	// reset INT reason				
		}
	else if (CANSTMOB & (1<<RXOK)) // signaling rxOK
		{
			 //get data of selected MOb
			 for (i=0; i<8; i++)		
		 		 recMsg.data[i] = CANMSG;
	
			 //get ID of selected MOb
			 recMsg.id = 0;
			 recMsg.id |= ((uint32_t) CANIDT1<<24);	//get identifier
			 recMsg.id |= ((uint32_t) CANIDT2<<16);
			 recMsg.id |= ((uint32_t) CANIDT3<<8);
			 recMsg.id |= (CANIDT4&0xF8);
			 recMsg.id >>= 3;


		 CANSTMOB &= ~(1<<RXOK);					// reset INT reason 	
		 CANCDMOB = (1<<CONMOB1) | (1<<IDE) | (8); 	// re-enable RX, reconfigure MOb IDE=1
		}

	else if (CANSTMOB & (1<<AERR))  // Acknowledge Error
		{
		 	CANSTMOB &= ~(1<<AERR);	// reset INT reason		 		
		}

	CANPAGE = save_canpage;   	// restore CANPAGE
}


/*******************************************************************
CAN initialization
*******************************************************************/
void can_init( void)
{
uint8_t mob;

  CANGCON |= (1<<SWRES);		// reset the CAN controller
  
  CANGCON = 0x00;				// reset the general control register
  CANGIT  = 0x00;				// reset the general interrupt register
   	
  CANSIT2 = 0x00;				// reset the status interrupt registers
  CANSIT1 = 0x00;

  //Enable CAN interrupts globally, set enable all interrupts except CANtimer overrun interrupt
  CANGIE = 0xfe;	//(1<<ENIT) | (1<<ENRX) | (1<<ENTX) |(1<<ENERR);//
  
  //Set MObs for which interrupts are enabled
  CANIE2 = (1<<IEMOB0) |  (1<<IEMOB1) |  (1<<IEMOB2) |  (1<<IEMOB3); 		
  CANIE1 = 0;

  //for all Message Objects: set the StatusRegister CANSTMOB to zero; Disable MOb CANCDMOB=0, (CONMOB1:0=00)
  for (mob = 0; mob < NO_MOBS; mob++)
  {
     CANPAGE  = (mob << 4);  //CANPAGE ist der Pointer fuer das gewuenschte MOB
	 CANIDT1 = 0x00;		//reset ID-Tag
	 CANIDT2 = 0x00;
	 CANIDT3 = 0x00;
	 CANIDT4 = 0x00;

	 CANIDM1 = 0x00;		//reset ID-Mask
	 CANIDM2 = 0x00;
	 CANIDM3 = 0x00;
	 CANIDM4 = 0x00;

     CANSTMOB = 0x00;		//reset MOb status
     CANCDMOB = 0x00; 		//disable MOb
  }

 //http://karmacarpentry.com/can_calc.htm
		
	
  CANBT1 = 0x26;	// set Baud Rate Prescaler for CAN controller bit timing (page236, table on page261)
  CANBT2 = 0x04;	// set propagation time segment (page232, table on page261)
  CANBT3 = 0x13;	// set PHaseSegment2 and PHaseSegment1 (page233, table on page261)
   
  CANTCON = 0xFF; 	// CAN timer prescaler 256. Can be used for time stamping
       
  CANGCON |= (1<<ENASTB);	// Set CAN-driver in enable mode (not standby-mode)
  	
  // wait until module is ready EnableFlag is on.
  while (!(CANGSTA & (1<<ENFG)));

  can_init_mob_rec(0x02); //setze MOB2 fuer den Empfang

//---------------- CAN CONTROLLER IS NOW INITIALISED/CONFIGURED 50kBits/s ---------------

    
}//can_init


/*******************************************************************
CAN MOB x  Receive initialization
*******************************************************************/
void can_init_mob_rec(uint8_t mob)
{
CAN_messageType msg;

//select MOb to be configured for receiving messages with some more IDs -----------------------

	//configure  MOb 
	CANPAGE = (mob<<4);				// select MOb page	
	
	msg.id = 0x80;			// define an ID for the message
	CANIDT4 = (msg.id << 3);
	CANIDT3 = msg.id >> 5;	
	CANIDT2 = msg.id >> 13;	
	CANIDT1 = msg.id >> 21;	

	//receive all messages on the bus
	msg.msk = 0xFFFFFF80;		// set IDmask to receive IDs from 0x0080...0x00FF
	CANIDM4 = (msg.msk << 3)| (1<<IDEMSK);	// set IDEMSK to 1 -> extended identifier
	CANIDM3 = msg.msk >> 5;
	CANIDM2 = msg.msk >> 13;
	CANIDM1 = msg.msk >> 21;

	// configure message as receive-msg, Extended frame format, data length code=8 
	// (see CANCDMOB register, page257)
	CANCDMOB = (1<<CONMOB1) | (1<<IDE) | (0x08);

    
}//can_init_mob_rec






/*******************************************************************
CAN transmission 
*******************************************************************/
void can_tx (CAN_messageType msg)
{	
uint8_t i, mob;	

	//select MOb to be sent, see define
	mob=TX_MOB;

	//enable MOb number mob, auto increment index, start with index = 0
	CANPAGE = (mob<<4);
	
	//set IDE bit, length = 8
	CANCDMOB = (1<<IDE) | (8);			
	
	//write 29 Bit identifier to MOb-ID-Tag
	msg.id <<= 3;								
	CANIDT4 = (unsigned char) (msg.id&0xF8);
	CANIDT3 = (unsigned char) (msg.id>>8);
	CANIDT2 = (unsigned char) (msg.id>>16);
	CANIDT1 = (unsigned char) (msg.id>>24);
	
	//put data in mailbox
	for (i=0; i<8; i++)							
		CANMSG = msg.data [i];
	
	//wait until transmit possible (TXBSY==0)
	while (CANGSTA & (1<<TXBSY));
	
	//enable transmission. After the tx is complete the TXOK bit is cleared in the ISR
	CANCDMOB |= (1<<CONMOB0);											

}//can_tx


/*******************************************************************
MAIN PROGRAM ENTRY POINT
*******************************************************************/
int main_new (void) 
{
CAN_messageType msg,msg0;

memset(&msg,0x00,sizeof(CAN_messageType)); //af
memset(&msg0,0x00,sizeof(CAN_messageType)); //af

//uint8_t aux=1,
uint8_t mob;

	
	can_init();						//initialize CAN driver
	sei();							//globally enable interrupts

// create CAN_package to be sent
	msg.id = 0x80;
	msg.length = 8;
	msg.data[0] = 0x01;
	msg.data[1] = 0x02;
	msg.data[2] = 0x01;
	msg.data[3] = 0x02;
	msg.data[4] = 0x01;
	msg.data[5] = 0x02;
	msg.data[6] = 0x01;
	msg.data[7] = 0x02;
	
// select MOb to be configured for receiving a message with a certain ID messages --------
	mob = 1;

	//configure  MOb
	CANPAGE = (mob<<4);				// select MOb page	
	
	msg0.id = 0x00000091;			// define an ID for the message
	CANIDT4 = msg0.id << 3;		
	CANIDT3 = msg0.id >> 5;	
	CANIDT2 = msg0.id >> 13;	
	CANIDT1 = msg0.id >> 21;	

	// define an ID mask for the MOb. 
	msg0.msk = 0xFFFFFFFF;			// set IDmask to receive (only ID 0x91)
	CANIDM4 = (msg0.msk << 3) | (1<<IDEMSK); // set IDEMSK to 1 -> extended identifier
	CANIDM3 = msg0.msk >> 5;
	CANIDM2 = msg0.msk >> 13;
	CANIDM1 = msg0.msk >> 21;

	// configure message as receive-msg, Extended frame format, data length code=8 
	// (see CANCDMOB register, page257)
	CANCDMOB = (1<<CONMOB1) | (1<<IDE) | (0x08);
// --------------------------------------------------------------------------------------------
	
//select MOb to be configured for receiving messages with some more IDs -----------------------
	mob = 2;

	//configure  MOb 
	CANPAGE = (mob<<4);				// select MOb page	
	
	msg0.id = 0x80;			// define an ID for the message
	CANIDT4 = (msg0.id << 3) ;		
	CANIDT3 = msg0.id >> 5;	
	CANIDT2 = msg0.id >> 13;	
	CANIDT1 = msg0.id >> 21;	

	//receive all messages on the bus
	msg0.msk = 0xFFFFFFF0;		// set IDmask to receive IDs from 0x80...0x8F
	CANIDM4 = (msg0.msk << 3)| (1<<IDEMSK);	// set IDEMSK to 1 -> extended identifier
	CANIDM3 = msg0.msk >> 5;
	CANIDM2 = msg0.msk >> 13;
	CANIDM1 = msg0.msk >> 21;

	// configure message as receive-msg, Extended frame format, data length code=8 
	// (see CANCDMOB register, page257)
	CANCDMOB = (1<<CONMOB1) | (1<<IDE) | (0x08);
// --------------------------------------------------------------------------------------------

	
return 0;
}//main





/*******************************************************************
Transfer from can to IO handling
*******************************************************************/



void can_advice(uint8_t port,uint8_t time)
{

CAN_messageType TxMsg;

memset(&TxMsg,0x00,sizeof(CAN_messageType));


	TxMsg.id = 0x91;
	TxMsg.length = 8;
	TxMsg.data[0] = TYPE_ROLLO;
	TxMsg.data[1] = port;
	TxMsg.data[2] = time;
	TxMsg.data[3] = 0x00;
	TxMsg.data[4] = 0x00;
	TxMsg.data[5] = 0x00;
	TxMsg.data[6] = 0x00;
	TxMsg.data[7] = 0x00;

can_tx(TxMsg);

return;
}

void can_message(uint8_t packet[8])
{
CAN_messageType TxMsg;

memset(&TxMsg,0x00,sizeof(CAN_messageType));


	TxMsg.id = 0x91;
	TxMsg.length = 8;
	TxMsg.data[0] = TYPE_ROLLO_MULTI;
	TxMsg.data[1] = packet[1];
	TxMsg.data[2] = packet[2];
	TxMsg.data[3] = packet[3];
	TxMsg.data[4] = packet[4];
	TxMsg.data[5] = packet[5];
	TxMsg.data[6] = packet[6];
	TxMsg.data[7] = packet[7];

can_tx(TxMsg);

return;
}


void can_job(void)
{
if (recMsg.id)
{
	can_to_io(recMsg.data);
	memset(&recMsg,0x00,sizeof(CAN_messageType));
}
return;
}
